using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;

namespace CommandReceiver
{

    public delegate void TcpAcceptEventHandler(Object sender, Socket socket);

    public class TcpServer
    {
        public event TcpAcceptEventHandler Accept;

        protected TcpAsyncListener listener;

        private IPAddress address;
        private IPEndPoint endpoint;

        private bool stop = false;

        public TcpServer(int port)
        {
            this.endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.21"), port);
        }

        public void Start()
        {
            listener = new TcpAsyncListener(endpoint);
            listener.Start();
            listener.BeginAcceptSocket(new AsyncCallback(this.OnAcceptSocket), listener);

            endpoint.Port = listener.LocalEndPoint.Port;

        }

        protected virtual void OnAcceptSocket(IAsyncResult result)
        {
            try
            {
                if (stop == false)
                {
                    TcpAsyncListener listener = (TcpAsyncListener)result.AsyncState;
                    Socket socket = listener.EndAcceptSocket(result);

                    listener.BeginAcceptSocket(new AsyncCallback(this.OnAcceptSocket), listener);
                    if (socket != null)
                    {
                        if (null != Accept)
                        {
                            Accept(this, socket);
                        }
                        else
                        {
                            socket.Shutdown(SocketShutdown.Both);
                            socket.Close();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        public virtual void Stop()
        {
            stop = true;
            this.listener.Stop();
        }
    }

    public class TcpAsyncListener : TcpListener
    {

        private delegate Socket AcceptSocketDelegate();

        private delegate TcpClient AcceptTcpClientDelegate();

        private AcceptSocketDelegate acceptSocket;

        private AcceptTcpClientDelegate acceptTcpClient;

        public TcpAsyncListener(IPEndPoint endpoint)
            : base(endpoint)
        {
        }

        public TcpAsyncListener(IPAddress address, int port)
            : base(address, port)
        {
        }

        public IAsyncResult BeginAcceptSocket(AsyncCallback callback, Object state)
        {
            if (acceptSocket == null)
                acceptSocket = new AcceptSocketDelegate(this.AcceptSocket);

            return acceptSocket.BeginInvoke(callback, state);
        }

        public IAsyncResult BeginAcceptTcpClient(AsyncCallback callback, Object state)
        {
            if (null == acceptTcpClient)
                acceptTcpClient = new AcceptTcpClientDelegate(this.AcceptTcpClient);

            return acceptTcpClient.BeginInvoke(callback, state);
        }


        // The code seems to hang right here.. But it works with 0.26
        //
        //
        public Socket EndAcceptSocket(IAsyncResult result)
        {
            Console.WriteLine("{0}: Calling EndInvoke", "EndAcceptSocket");
            Socket s = acceptSocket.EndInvoke(result);
            Console.WriteLine("{0}: EndInvoke finished", "EndAcceptSocket");
            return s;
        }

        public TcpClient EndAcceptTcpClient(IAsyncResult result)
        {
            return acceptTcpClient.EndInvoke(result);
        }

        public IPEndPoint LocalEndPoint
        {
            get
            {
                return (IPEndPoint)this.Server.LocalEndPoint;
            }
        }
    }
}

